/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

#include"PublicIPTool.h"
#include"PublicLog.h"
#include<stdlib.h>
#include<string.h>
#include"PublicNetHead.h"
#ifdef __MINGW32__
char*sock_startup(void){
    WORD            VersionRequested;
    WSADATA         stWSAData;
    int             i;
    static char     errmsg[100];
/* winsock 1: use MAKEWORD(1,1) */
/* winsock 2: use MAKEWORD(2,2) */
    VersionRequested = MAKEWORD(2,2);
    i = WSAStartup(VersionRequested, &stWSAData);
    if (i != 0) {
        if (i == WSAVERNOTSUPPORTED)
            sprintf(errmsg, "Unable to init. socket lib, does not support 1.1");
        else 
            sprintf(errmsg, "Socket Startup error %d", i);
        return (errmsg);
    }
    return (NULL);
}
void sock_cleanup(){
    WSACleanup();
}
uint32_t inet_network(const char*IP){
    uint32_t check_addr=inet_addr(IP);
    check_addr=htonl(check_addr);
    return check_addr;
}
#else
char*sock_startup(void){
	return NULL;
}
void sock_cleanup(){
}
#endif

#define HTON16(x)  ((x>>8&0xff)|(x<<8&0xff00))
#define HTON32(x)  ((x>>24&0xff)|(x>>8&0xff00)|(x<<8&0xff0000)|(x<<24&0xff000000))
uint16_t hton16(uint16_t data){
	return HTON16(data);
}
uint32_t hton32(uint32_t data){
	return HTON32(data);
}
uint32_t random(uint32_t randata){
	if(randata==0)randata=1;
	return rand()%randata;
}
const char*GetIPByHostID(char*IP,uint32_t host){
	struct in_addr addr4;
	addr4.s_addr=host;
	static char sysip[40]={0};
	char *ptr=sysip;
	if(IP!=NULL){
		ptr=IP;
	}
	return inet_ntop(AF_INET,&addr4,ptr,16);		
}
const char*GetIPByHostIDV6(char*IP,uint8_t host[]){
	struct in6_addr addr6;
	memcpy(addr6.s6_addr,host,sizeof(struct in6_addr));
	static char sysip[40]={0};
	char *ptr=sysip;
	if(IP!=NULL){
		ptr=IP;
	}
	return inet_ntop(AF_INET6,&addr6,ptr,40);		
}
const char*GetIPByNetWorkID(char*IP,uint32_t net){
//先换成主机序	
	struct in_addr addr4;
	addr4.s_addr=htonl(net);
	static char sysip[16]={0};
	char *ptr=sysip;
	if(IP!=NULL){
		ptr=IP;
	}
	return inet_ntop(AF_INET,&addr4,ptr,16);
}
uint32_t inet_network_ex(const char*IP){
	return inet_network(IP);
}
int IsIPV4(const char*ip){
    struct in_addr addr4;	
    return inet_pton(AF_INET,ip,&addr4);
}
int IsIPV6(const char*ip){
	struct in6_addr addr6; 
	return inet_pton(AF_INET6,ip,&addr6);
}
int IsPublicIPV6(const char*ip){
	struct in6_addr addr6; 
	int ret=inet_pton(AF_INET6,ip,&addr6);
	if(ret==1){
		//INFO("8:0x%x 16:0x%x 32:0x%x",addr6.s6_addr[0],addr6.s6_addr16[0],addr6.s6_addr32[0]);
		//开头为2000到3fff之间为公网
		if((addr6.s6_addr[0]>0x19)&&(addr6.s6_addr[0]<0x40)){
			return 1;
		}	
		return 0;
	}
	return -1;
}

static const uint32_t CheckIPType[][2]={
    {0x7F000000,0xFF000000},//"127.x.x.x","255.0.0.0"
    {0x0A000000,0xFF000000},//"10.x.x.x","255.0.0.0"
    {0xAC100000,0xFFF00000},//"172.16.x.x~172.31.x.x","255.240.0.0"
    {0xC0A80000,0xFFFF0000},//"192.168.x.x","255.255.0.0"
    {0xA9FE0000,0xFFFF0000},//"169.254.0.0","255.255.0.0"
    {0xFFFFFFFF,0xFFFFFFFF},//"255.255.255.255"
    {0x00000000,0x00000000}
};
//检测内网IP
static int bCheckLanIP=1;
void SetCheckLanIP(int bCheck){
    bCheckLanIP=bCheck;
}
int  IsPublicIPV4(const char*IP){
//判断是否是IPV4	
    if(IsIPV4(IP)==1){
//无需判断内网直接认为是公网		
        if(bCheckLanIP==0){
			return 1;
		}
        int i=0;
        uint32_t check_addr=inet_network(IP);
        if(check_addr==0||check_addr==0xFFFFFFFF)
            return -1;
        while(CheckIPType[i][0]!=0){
            if((check_addr&CheckIPType[i][1])==(CheckIPType[i][0])){
                return 0;
            }
            i++;
        }
		return 1;
    }
    return -1;
}
int GetIPType(const char*ip){
	if(IsIPV4(ip)==1){
		return 4;
	}else
	if(IsIPV6(ip)==1){
		return 6;
	}	
	return -1;
}
void ShowAllIP(const char*IP,const char*Mask){
    u_long uIP=inet_network(IP);
    u_long uMask=inet_network(Mask);
    u_long MaxI=0xFFFFFFFFU-uMask;
    in_addr ChildIP={0};
    INFO("MaxI:%ld",MaxI);
    u_long i=0;
    while(i<=MaxI){
        ChildIP.s_addr=ntohl(uIP+i);
        INFO("IP:%s",inet_ntoa(ChildIP));
        i++;
    }
}
#ifdef __MINGW32__
SETIPLIST GetLocalIPList(){
    SETIPLIST iplist;
    char buffer[256] = {0};  
    if(gethostname(buffer,256)==0){
        struct addrinfo hinsAddr;  
        memset(&hinsAddr, 0, sizeof(hinsAddr));  
        hinsAddr.ai_family = AF_INET;  
        hinsAddr.ai_socktype = SOCK_STREAM;  
        hinsAddr.ai_protocol = IPPROTO_TCP;  
        struct addrinfo *outAddr;  
        int retVal = 0;  
        retVal = getaddrinfo(buffer, NULL, &hinsAddr, &outAddr);  
        if (retVal!=0){  
            printf("getaddrinfo failed\n");  
            return iplist;  
        }    
        struct addrinfo *nextAddr =outAddr;  
        while (nextAddr != NULL){  
            struct sockaddr_in*addrIn = (struct sockaddr_in *)nextAddr->ai_addr;  
            char *ip = inet_ntoa(addrIn->sin_addr);  
            iplist.insert(ip);
//          printf("%s %s\n", ip,nextAddr->ai_canonname);  
            nextAddr = nextAddr->ai_next;  
        }  
        freeaddrinfo(outAddr);
    }
	return iplist;
}
#else
#include<ifaddrs.h>
#include<net/if.h>
const char*GetIPV6DeviceName(int ipflag){
	static char  Device[256]={0};
	struct ifaddrs*ifinfo=NULL;
    getifaddrs(&ifinfo);
	memset(Device,0,sizeof(Device));
    struct ifaddrs*Pos=ifinfo;
    while(Pos){        
		if((Pos->ifa_addr->sa_family==AF_INET6)&&((Pos->ifa_flags&IFF_LOOPBACK)==0)){
			char ipv6[40]={0};
			inet_ntop(AF_INET6,&((struct sockaddr_in6*)(Pos->ifa_addr))->sin6_addr,ipv6,40);
			if(IsPublicIPV6(ipv6)==1&&(ipflag&IP_FLAG_IPV6PUB)){
				strcpy(Device,Pos->ifa_name);
				break;
			}else
			if(IsPublicIPV6(ipv6)==0&&(ipflag&IP_FLAG_IPV6PRI)){
				strcpy(Device,Pos->ifa_name);
				break;
			}
        }	
        Pos=Pos->ifa_next;
    }
    if(ifinfo)freeifaddrs(ifinfo);
	return Device;
}
SETIPLIST GetLocalIPList(int ipflag){
	SETIPLIST iplist;
    struct ifaddrs*ifinfo=NULL;
    getifaddrs(&ifinfo);
    struct ifaddrs*Pos=ifinfo;
    while(Pos){
        if((Pos->ifa_addr->sa_family==AF_INET)&&((Pos->ifa_flags&IFF_LOOPBACK)==0)&&(CHEKFLAGIPV4(ipflag))){
			char ipv4[16]={0};
			inet_ntop(AF_INET,&((struct sockaddr_in*)(Pos->ifa_addr))->sin_addr,ipv4,16);
			if(IsPublicIPV4(ipv4)==1&&(ipflag&IP_FLAG_IPV4PUB)){
				iplist.insert(ipv4);
			}else
			if(IsPublicIPV4(ipv4)==0&&(ipflag&IP_FLAG_IPV4PRI)){
				iplist.insert(ipv4);
			}
        }else
		if((Pos->ifa_addr->sa_family==AF_INET6)&&((Pos->ifa_flags&IFF_LOOPBACK)==0)&&(CHEKFLAGIPV6(ipflag))){
			char ipv6[40]={0};
			inet_ntop(AF_INET6,&((struct sockaddr_in6*)(Pos->ifa_addr))->sin6_addr,ipv6,40);
			if(IsPublicIPV6(ipv6)==1&&(ipflag&IP_FLAG_IPV6PUB)){
				iplist.insert(ipv6);
			}else
			if(IsPublicIPV6(ipv6)==0&&(ipflag&IP_FLAG_IPV6PRI)){
				iplist.insert(ipv6);
			}
        }	
        Pos=Pos->ifa_next;
    }
    if(ifinfo)freeifaddrs(ifinfo);
    return iplist;
}
#endif
SETIPLIST GetPublicIPList(){
    SETIPLIST publiciplist=GetLocalIPList(IP_FLAG_IPV4PUB);
    if(publiciplist.empty()){
		publiciplist=GetLocalIPList(IP_FLAG_IPV4PRI);
    }
    return publiciplist;
}
int IsSupportIPV6(){
	SETIPLIST publiciplist=	GetLocalIPList(IP_FLAG_IPV6PUB);
	if(publiciplist.empty()){
		return 0;
	}
	return 1;
}
std::string GetSimpleIPV6(const char*ip){
	std::string realip="";
	struct in6_addr addr6; 
	inet_pton(AF_INET6,ip,&addr6);
	char ipv6[40]={0};
	inet_ntop(AF_INET6,&addr6,ipv6,40);
	realip=ipv6;
	return realip;
}
std::string GetMainLocalIP(){
    std::string localip="0.0.0.0";
    SETIPLIST publicipllist=GetPublicIPList();
    do{
        SETIPLIST::iterator it=publicipllist.begin();
        if(it!=publicipllist.end()){
			localip=it->c_str();
        }
    }while(0);
    return localip;
}
static int g_enableping=1;
//加锁易锁住程序
//中断PublicNet的使用
void DisablePingThread(){
    g_enableping=0;
}
//检查是否正常使用PublicNet库
int  EnablePingThread(){
    return g_enableping;
}
uint16_t Check_SUM(uint16_t*data,int len){
    int nleft=len;
    uint16_t*p=data;
    uint16_t answer=0;
    int sum=0;
    while(nleft>1){
		sum+=*p++;
		nleft-=2;
    }
    if(nleft==1)
       sum+=hton16(*(u_char*)p<<8);
    sum = (sum >> 16) + (sum & 0xffff);
    sum += (sum >> 16);
    answer = ~sum;
    return answer;
}

